/***************************************** 
 * Desc: UGUI自定义的Scroller
 * @Author: GSan
 * @Email: 2087653648@qq.com
 * CreateDate: 2020-07-25 18:11:59
*****************************************/

using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Common.UGUI.View {

	[RequireComponent(typeof(Image))]
	public class UGUIScroller : UGUIPanel {

        #region 域

        public bool IfPanelSizeAffectContent {
            get {
                return _ifPanelSizeAffectContent;
            }
            set {
                _ifPanelSizeAffectContent = value;
            }
        }

        public bool IfNeedStick {

            get {
                return _ifNeedStick;
            }

            set {
                SetIfNeedStick(true);
            }
        }

        public float Progress {

            get {
                return _progress;
            }

            set {
                SetProgress(value);
            }
        }

        public float Sensitivity {
            get {
                return _sensitivity;
            }
            set {
                _sensitivity = value;
            }
        }

        public Vector2 Size {
            get {
                return new Vector2(_width, _height);
            }
            set {
                SetSize(value);
            }
        }

        /// <summary>
        /// 当进度条进度发生改变时
        /// </summary>
        public Action<float> OnProgressChanged { get; set; }

        protected RectTransform _stickContent = null;
        protected RectTransform _scrollContent = null;
        protected RectTransform _scrollContentChild = null;

        [SerializeField]
        private bool _ifPanelSizeAffectContent = true;
        [SerializeField]
        private bool _ifNeedStick = false;

        [SerializeField]
        private float _width = 0;
        [SerializeField]
        private float _height = 0;

        [SerializeField]
        [Range(0f, 100f)]
        private float _progress = 0f;

        private float _screenX = 0f;

        [SerializeField]
        [Header("灵敏度")]
        private float _sensitivity = 1f;

        #endregion

        #region Unity生命周期

        protected override void OnAwake() {

            CheckNeededPart();

            SetSize(Size);

            _screenX = Screen.width;

            SetColor(Color.clear);
        }

#if UNITY_EDITOR
        private void OnGUI() {
            if (!Application.isPlaying) {
                CheckNeededPart();
            }
        }
#endif

        #endregion

        #region 接口

        /// <summary>
        /// 设置进度条宽高，小于0的话会默认设置为0
        /// </summary>
        /// <param name="size"></param>
        public void SetSize(Vector2 size) {

            _width = Mathf.Max(size.x, 0);
            _height = Mathf.Max(size.y, 0);
            RectTransform.sizeDelta = Size;

            if(_ifPanelSizeAffectContent && _scrollContent != null) {
                _scrollContent.sizeDelta = Size;
            }
        }

        /// <summary>
        /// 设置是否需要控制点图标
        /// </summary>
        public void SetIfNeedStick(bool ifNeedStick) {

            _ifNeedStick = ifNeedStick;

            if (_ifNeedStick) {

                if(_stickContent == null) {

                    Transform stick = Transform.Find("stick");

                    if (stick != null) {

                        RectTransform rect = (RectTransform)stick;

                        if(rect == null) {
                         
                            Destroy(stick.gameObject);

                            NewStickContent();
                        } else {
                            
                            FixStickContentStatus(rect);
                        }
                    } else {

                        NewStickContent();
                    }
                }
            } else {

                if(_stickContent != null) {

#if !UNITY_EDITOR
                    Destroy(_stickContent.gameObject);
#else
                    DestroyImmediate(_stickContent.gameObject);
#endif

                    _stickContent = null;
                }
            }
        }

        /// <summary>
        /// 设置进度条进度
        /// </summary>
        /// <param name="percentage">百分比，范围为 0~1 </param>
        public void SetProgress(float percentage) {

            percentage = Mathf.Max(percentage, 0);
            percentage = Mathf.Min(percentage, 1f);

            if (_scrollContentChild != null) {
                _scrollContentChild.sizeDelta = new Vector2(_width * percentage, _height);
            }

            if (_stickContent != null) {
                _stickContent.anchoredPosition = new Vector2(_width * percentage, 0);
            }

            _progress = percentage;
        }

#endregion

#region 滚动内容

        /// <summary>
        /// 生成一个新的滚动内容（带子节点）
        /// </summary>
        protected void NewScrollContent() {
           
            GameObject scrollContent = new GameObject("content");
            
            scrollContent.AddComponent<RectTransform>();
            
            scrollContent.transform.SetParent(Transform, false);
            
            _scrollContent = (RectTransform)scrollContent.transform;

            FixScrollContentStatus(_scrollContent);

            NewScrollContentChild();
        }

        /// <summary>
        /// 重置滚动内容的各项参数到默认值
        /// </summary>
        protected void FixScrollContentStatus(RectTransform scrollContent) {

            if (scrollContent.GetComponent<Image>() == null) {
                scrollContent.gameObject.AddComponent<Image>().raycastTarget = false;
            } else {
                scrollContent.GetComponent<Image>().raycastTarget = false;
            }

            if (scrollContent.GetComponent<Mask>() == null) {
                scrollContent.gameObject.AddComponent<Mask>();
            }

            scrollContent.anchoredPosition = Vector2.zero;
        }

        /// <summary>
        /// 生成滚动内容子节点
        /// </summary>
        protected void NewScrollContentChild() {

            if (_scrollContent != null) {
            
                GameObject scrollContentChild = new GameObject("child");
                
                scrollContentChild.AddComponent<RectTransform>();

                scrollContentChild.transform.SetParent(_scrollContent, false);
                
                _scrollContentChild = (RectTransform)scrollContentChild.transform;

                FixScrollContentChildStatus(_scrollContentChild);
            }
        }

        /// <summary>
        /// 重置滚动内容子节点的各项参数到默认值
        /// </summary>
        protected void FixScrollContentChildStatus(RectTransform scrollContentChild) {

            if (_scrollContent != null) {

                if(scrollContentChild.GetComponent<Image>() == null) {
                    scrollContentChild.gameObject.AddComponent<Image>().raycastTarget = false;
                } else {
                    scrollContentChild.GetComponent<Image>().raycastTarget = false;
                }

                scrollContentChild.anchorMin = new Vector2(0, 0.5f);
                scrollContentChild.anchorMax = new Vector2(0, 0.5f);
                scrollContentChild.pivot = new Vector2(0, 0.5f);
                scrollContentChild.anchoredPosition = Vector2.zero;
                scrollContentChild.sizeDelta = new Vector2(0, _scrollContent.sizeDelta.y);
            }
        }

#endregion

#region 滚动拐点

        /// <summary>
        /// 生成一个新的拖动点内容
        /// </summary>
        protected void NewStickContent() {

            GameObject stick = new GameObject("stick");

            stick.AddComponent<RectTransform>();

            stick.transform.SetParent(Transform, false);

            _stickContent = (RectTransform)stick.transform;

            FixStickContentStatus(_stickContent);
        }

        /// <summary>
        /// 重置拖动点的各项参数到默认值
        /// </summary>
        protected void FixStickContentStatus(RectTransform stickContent) {

            if(stickContent.GetComponent<Image>() == null) {
                stickContent.gameObject.AddComponent<Image>().raycastTarget = false;
            } else {
                stickContent.GetComponent<Image>().raycastTarget = false;
            }

            stickContent.anchorMin = new Vector2(0, 0.5f);
            stickContent.anchorMax = new Vector2(0, 0.5f);
            stickContent.pivot = new Vector2(0.5f, 0.5f);
            stickContent.anchoredPosition = Vector2.zero;
        }

#endregion

#region 事件回调

        private Vector2 _beforePointerPosition = Vector2.zero;
        private Vector2 _nowPointerPosition = Vector2.zero;

        public override void OnPointerDown(PointerEventData eventData) {
            _beforePointerPosition = eventData.position;
            _nowPointerPosition = eventData.position;
        }

        public override void OnDrag(PointerEventData eventData) {

            _beforePointerPosition = _nowPointerPosition;
            _nowPointerPosition = eventData.position;

            float deltaX = (_nowPointerPosition - _beforePointerPosition).x;

            float xSpeed = deltaX / _screenX;

            xSpeed *= _sensitivity;

#if UNITY_EDITOR
            //Debug.Log("UGUIScroller xSpeed is " + xSpeed);
#endif

            if (deltaX > 0) {

                float progress = Mathf.SmoothStep( _progress, 1, xSpeed);

                SetProgress(progress);

                if(OnProgressChanged != null) {

                    OnProgressChanged(_progress);
                }
            } else if(deltaX < 0){

                float progress = Mathf.SmoothStep(_progress, 0, Math.Abs(xSpeed));

                SetProgress(progress);

                if (OnProgressChanged != null) {

                    OnProgressChanged(_progress);
                }
            }
        }

        public override void OnPointerUp(PointerEventData eventData) {
            _beforePointerPosition = Vector2.zero;
            _nowPointerPosition = Vector2.zero;
        }

#endregion

#region 私有方法

        /// <summary>
        /// 检查组成UGUIScroller所需要的内容
        /// </summary>
        protected void CheckNeededPart() {

            Transform content = Transform.Find("content");
            _scrollContent = content == null ? null : (RectTransform)content;

            if (_scrollContent == null) {
                
                NewScrollContent();

            } else {

                FixScrollContentStatus(_scrollContent);

                content = _scrollContent.Find("child");

                if (content != null) {

                    _scrollContentChild = (RectTransform)content.transform;

                    if (_scrollContentChild != null) {

                        FixScrollContentChildStatus(_scrollContentChild);
                    } else {

                        Destroy(content);

                        NewScrollContentChild();
                    }
                } else {

                    NewScrollContentChild();
                }
            }

            if (_ifNeedStick) {

                SetIfNeedStick(true);
            } else {

                SetIfNeedStick(false);
            }
        }

#endregion
    }
}
